/*!	 _handle.h
**
**	 Template Object Handle Implementation
**	\internal
**
**	Copyright (c) 2002 Robert B. Quattlebaum Jr.
**	Copyright (c) 2007, 2008 Chris Moore
**
**	This package is free software; you can redistribute it and/or
**	modify it under the terms of the GNU General Public License as
**	published by the Free Software Foundation; either version 2 of
**	the License, or (at your option) any later version.
**
**	This package is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
**	General Public License for more details.
**
**	\note
**		This is an internal header file, included by other ETL headers.
**		You should not attempt to use it directly.
*/

#ifndef __ETL__HANDLE_H
#define __ETL__HANDLE_H

#include <cassert>
#include <typeinfo>

#define ETL_SELF_DELETING_SHARED_OBJECT

#ifdef NDEBUG
#define assert_cast		static_cast
#else
#define assert_cast		dynamic_cast
#endif

_ETL_BEGIN_NAMESPACE

// Forward Declarations
template <class T> class handle;
template <class T> class loose_handle;
template <class T> class rhandle;

/*!	\class	shared_object _handle.h	ETL/handle
**		Shared Object Base Class
**	\see handle, loose_handle
**	\writeme
*/
class shared_object
{
private:
    mutable int refcount;
#ifdef ETL_LOCK_REFCOUNTS
    mutable etl::mutex mtx;
#endif

protected:
    shared_object(): refcount(0) { }
    shared_object(const shared_object&): refcount(0) { }
    shared_object& operator= (const shared_object&)
    {
        return *this;
    }

#ifdef ETL_SELF_DELETING_SHARED_OBJECT
    virtual ~shared_object() { }
#else
    ~shared_object() { }
#endif

public:
    virtual void ref()const
    {
#ifdef ETL_LOCK_REFCOUNTS
        etl::mutex::lock lock(mtx);
#endif
        assert(refcount >= 0);
        refcount++;
    }

    // Returns \c false if object needs to be deleted
    virtual bool unref()const
    {
        bool ret = true;
        {
#ifdef ETL_LOCK_REFCOUNTS
            etl::mutex::lock lock(mtx);
#endif
            assert(refcount > 0);

            refcount--;

            if (refcount == 0) {
                ret = false;
#ifdef ETL_SELF_DELETING_SHARED_OBJECT
                refcount = -666;
#endif
            }
        }

#ifdef ETL_SELF_DELETING_SHARED_OBJECT

        if (!ret) {
            delete this;
        }

#endif
        return ret;
    }

    // Decrease reference counter without deletion of object
    // Returns \c false if references exeed and object should be deleted
    virtual bool unref_inactive()const
    {
        bool ret = true;
        {
#ifdef ETL_LOCK_REFCOUNTS
            etl::mutex::lock lock(mtx);
#endif
            assert(refcount > 0);

            refcount--;

            if (refcount == 0) {
                ret = false;
            }
        }

        return ret;
    }

    int count()const
    {
        return refcount;
    }

}; // END of class shared_object

/*!	\class	virtual_shared_object _handle.h	ETL/handle
**		Virtual Shared Object Base Class
**	\see handle, loose_handle
**	\writeme
*/
class virtual_shared_object
{
protected:
    virtual_shared_object() { }
    virtual_shared_object(const virtual_shared_object&) { }
    virtual_shared_object& operator= (const virtual_shared_object&)
    {
        return *this;
    }
public:
    virtual ~virtual_shared_object() { }
    virtual void ref()const = 0;
    virtual bool unref()const = 0;
    virtual bool unref_inactive()const = 0;
    virtual int count()const = 0;
}; // END of class virtual_shared_object

/*!	\class	handle _handle.h	ETL/handle
**		Object Handle
**	\see shared_object, loose_handle
**	\writeme
*/
template <class T>
class handle
{
public:

    typedef T value_type;
    typedef T& reference;
    typedef const T& const_reference;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef int count_type;
    typedef int size_type;

protected:
#ifdef _DEBUG
public:
#endif
    value_type *obj;		// < Pointer to object

public:

    // Default constructor - empty handle
    handle(): obj(NULL) {}

    // Constructor that constructs from a pointer to new object
    handle(pointer x): obj(x)
    {
        if (obj) {
            obj->ref();
        }
    }

    // Default copy constructor
    handle(const handle<value_type> &x): obj(x.get())
    {
        if (obj) {
            obj->ref();
        }
    }

    // Handle is released on deletion
    ~handle()
    {
        detach();
    }

    // Template Assignment operator
    /*! \note This class may not be necessary, and may be removed
    **		at some point in the future.
    */


    // Assignment operator
    handle<value_type> &
    operator=(const handle<value_type> &x)
    {
        if (x.get() == obj) {
            return *this;
        }

        detach();

        obj = x.get();

        if (obj) {
            obj->ref();
        }

        return *this;
    }

    // Swaps the values of two handles without reference counts
    handle<value_type> &
    swap(handle<value_type> &x)
    {
        pointer ptr = x.obj;
        x.obj = obj;
        obj = ptr;
        return *this;
    }

    // Handle detach procedure
    /*! unref()'s the object and sets the internal object pointer to \c NULL */
    void
    detach()
    {
        pointer xobj(obj);
        obj = 0;
#ifdef ETL_SELF_DELETING_SHARED_OBJECT

        if (xobj) {
            xobj->unref();
        }

#else

        if (xobj && !xobj->unref()) {
            delete xobj;
        }

#endif
    }

    // This will be reintroduced with a new function

    void reset()
    {
        detach();
    }

    bool empty()const
    {
        return obj == 0;
    }

    // Creates a new instance of a T object and puts it in the handle.
    /*! Uses the default constructor */
    void spawn()
    {
        operator=(handle(new T()));
    }

    // Returns a constant handle to our object
    handle<const value_type> constant()const
    {
        assert(obj);
        return *this;
    }

    // Returns number of instances
    count_type
    count()const
    {
        return obj ? obj->count() : 0;
    }

    // Returns true if there is only one instance of the object
    bool
    unique()const
    {
        assert(obj);
        return count() == 1;
    }

    reference
    operator*()const
    {
        assert(obj);
        return *obj;
    }

    pointer
    operator->()const
    {
        assert(obj);
        return obj;
    }

    // More explicit bool cast
    operator bool()const
    {
        return obj != NULL;
    }

    operator handle<const value_type>()const
    {
        return handle<const value_type>(static_cast<const_pointer>(obj));
    }

    // <tt> static_cast\<\> </tt> wrapper
    template <class U> static handle<T> cast_static(const handle<U> &x)
    {
        return handle<T>(static_cast		<T*>(x.get()));
    }
    // <tt> dynamic_cast\<\> </tt> wrapper
    template <class U> static handle<T> cast_dynamic(const handle<U> &x)
    {
        return handle<T>(dynamic_cast	<T*>(x.get()));
    }
    // <tt> const_cast\<\> </tt> wrapper
    template <class U> static handle<T> cast_const(const handle<U> &x)
    {
        return handle<T>(const_cast		<T*>(x.get()));
    }
    // <tt> reinterpret_cast\<\> </tt> wrapper
    template <class U> static handle<T> cast_reinterpret(const handle<U> &x)
    {
        return handle<T>(reinterpret_cast<T*>(x.get()));
    }

    template <class U> static handle<T> cast_static(const loose_handle<U> &x);
    template <class U> static handle<T> cast_dynamic(const loose_handle<U> &x);
    template <class U> static handle<T> cast_const(const loose_handle<U> &x);
    template <class U> static handle<T> cast_reinterpret(const loose_handle<U> &x);

    template <class U> static handle<T> cast_static(const rhandle<U> &x);
    template <class U> static handle<T> cast_dynamic(const rhandle<U> &x);
    template <class U> static handle<T> cast_const(const rhandle<U> &x);
    template <class U> static handle<T> cast_reinterpret(const rhandle<U> &x);

    template <class U> static handle<T> cast_static(U* x);
    template <class U> static handle<T> cast_dynamic(U* x);
    template <class U> static handle<T> cast_const(U* x);
    template <class U> static handle<T> cast_reinterpret(U* x);

    // Returns pointer to the object that is being wrapped
    pointer get()const
    {
        return obj;
    }

    bool
    operator!()const
    {
        return !obj;
    }

    // static_cast<> overload -- Useful for implicit casts
    template <class U>
    operator handle<U>()const
    {
        return handle<U>(obj);
    }

    template<typename U>
    bool type_is() const
    {
        return dynamic_cast<const U*>(obj);
    }

    template<typename U>
    U* type_pointer() const
    {
        return dynamic_cast<U*>(obj);
    }

    template<typename U>
    bool type_equal() const
    {
        return typeid(*obj) == typeid(U);
    }
}; // END of template class handle

/*!	\class	rshared_object _handle.h	ETL/handle
**		Replaceable Shared Object Base Class
**	\see rhandle
**	\writeme
*/
class rshared_object : public shared_object
{
private:
    mutable int rrefcount;

public:
    void *front_;
    void *back_;

protected:
    rshared_object(): rrefcount(0), front_(0), back_(0) { }
    rshared_object(const rshared_object &other): shared_object(other), rrefcount(0), front_(0), back_(0) { }
    rshared_object& operator= (const rshared_object&)
    {
        return *this;
    }

public:
    virtual void rref()const
    {
        rrefcount++;
    }

    virtual void runref()const
    {
        assert(rrefcount > 0);
        rrefcount--;
    }

    int rcount()const
    {
        return rrefcount;
    }
}; // END of class rshared_object

/*!	\class	rhandle _handle.h	ETL/handle
**		Replaceable Object Handle
**	\see rshared_object, handle, loose_handle
**	\writeme
*/
template <class T>
class rhandle : public handle<T>
{
    friend class rshared_object;
public:

    typedef T value_type;
    typedef T& reference;
    typedef const T& const_reference;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef int count_type;
    typedef int size_type;

    using handle<value_type>::count;
    using handle<value_type>::unique;
    using handle<value_type>::operator bool;
    using handle<value_type>::get;
    using handle<value_type>::operator*;
    using handle<value_type>::operator->;



private:
    using handle<value_type>::obj;

    rhandle<value_type> *prev_;
    rhandle<value_type> *next_;

    void add_to_rlist()
    {

        assert(obj);
        obj->rref();

        // If this is the first reversible handle
        if (!obj->front_) {
            obj->front_ = obj->back_ = this;
            prev_ = next_ = 0;
            return;
        }

        prev_ = reinterpret_cast<rhandle<value_type>*>(obj->back_);
        next_ = 0;
        prev_->next_ = this;
        obj->back_ = this;
    }

    void del_from_rlist()
    {
        assert(obj);
        obj->runref();

        // If this is the last reversible handle
        if (obj->front_ == obj->back_) {
            obj->front_ = obj->back_ = 0;
            prev_ = next_ = 0;
            return;
        }

        if (!prev_) {
            obj->front_ = (void*)next_;
        } else {
            prev_->next_ = next_;
        }

        if (!next_) {
            obj->back_ = (void*)prev_;
        } else {
            next_->prev_ = prev_;
        }
    }

public:

    // Default constructor - empty handle
    rhandle() {}

    // Constructor that constructs from a pointer to new object
    rhandle(pointer x): handle<T>(x)
    {
        if (obj) {
            add_to_rlist();
        }
    }

    rhandle(const handle<value_type> &x): handle<T>(x)
    {
        if (obj) {
            add_to_rlist();
        }
    }

    // Default copy constructor
    rhandle(const rhandle<value_type> &x): handle<T>(x)
    {
        if (obj) {
            add_to_rlist();
        }
    }

    // Handle is released on deletion
    ~rhandle()
    {
        detach();
    }

    // Template Assignment operator
    /*! \note This class may not be necessary, and may be removed
    **		at some point in the future.
    */


    // Assignment operator
    rhandle<value_type> &
    operator=(const rhandle<value_type> &x)
    {
        if (x.get() == obj) {
            return *this;
        }

        detach();

        obj = x.get();

        if (obj) {
            obj->ref();
            add_to_rlist();
        }

        return *this;
    }

    rhandle<value_type>&
    operator=(const handle<value_type> &x)
    {
        if (x.get() == obj) {
            return *this;
        }

        detach();

        obj = x.get();

        if (obj) {
            obj->ref();
            add_to_rlist();
        }

        return *this;
    }

    rhandle<value_type>&
    operator=(value_type* x)
    {
        if (x == obj) {
            return *this;
        }

        detach();

        obj = x;

        if (obj) {
            obj->ref();
            add_to_rlist();
        }

        return *this;
    }

    // Handle release procedure
    /*! unref()'s the object and sets the internal object pointer to \c NULL */
    void
    detach()
    {
        if (obj) {
            del_from_rlist();
        }

        handle<value_type>::detach();
        obj = 0;
    }

    // This will be reintroduced with a new function

    void reset()
    {
        detach();
    }

    // Creates a new instance of a T object and puts it in the handle.
    /*! Uses the default constructor */
    void spawn()
    {
        operator=(handle<value_type>(new T()));
    }

    // Returns number of reversible instances
    count_type
    rcount()const
    {
        return obj ? obj->rcount() : 0;
    }

    // Returns true if there is only one instance of the object
    bool
    runique()const
    {
        assert(obj);
        return obj->front_ == obj->back_;
    }

    // \writeme
    int replace(const handle<value_type> &x)
    {
        assert(obj);
        assert(x.get() != obj);

        if (x.get() == obj) {
            return 0;
        }

        rhandle<value_type> *iter;
        rhandle<value_type> *next;

        iter = reinterpret_cast<rhandle<value_type>*>(obj->front_);

        assert(iter);

        next = iter->next_;

        int i = 0;
#ifndef NDEBUG
        pointer obj_ = obj;
#endif

        for (; iter; iter = next, next = iter ? iter->next_ : 0, i++) {
            assert(iter->get() == obj_);
            (*iter) = x;
        }

        assert(obj == x.get());

        return i;
    }

    // Swaps the values of two handles without reference counts
    /*!	\warning not yet implemented. \writeme */
    handle<value_type> &
    swap(handle<value_type> &x);

}; // END of template class rhandle

/*!	\class	loose_handle _handle.h	ETL/handle
**		Loose Object Handle
**	\see shared_object, handle
**	\writeme
*/
template <class T>
class loose_handle
{
public:

    typedef T value_type;
    typedef T& reference;
    typedef const T& const_reference;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef int count_type;
    typedef int size_type;

protected:
#ifdef _DEBUG
public:
#endif
    value_type *obj;		// < Pointer to object

public:

    // Default constructor - empty handle
    loose_handle(): obj(0) {}

    // Constructor that constructs from a pointer to new object
    loose_handle(pointer x): obj(x) { }

    // Default copy constructor
    loose_handle(const loose_handle<value_type> &x): obj(x.get()) { }

    loose_handle(const handle<value_type> &x): obj(x.get()) { }

    template <class U> const loose_handle<value_type> &
    operator=(const handle<U> &x)
    {
        if (x.get() == obj) {
            return *this;
        }

        obj = x.get();
        return *this;
    }

    template <class U> const loose_handle<value_type> &
    operator=(const loose_handle<U> &x)
    {
        if (x.get() == obj) {
            return *this;
        }

        obj = x.get();
        return *this;
    }

    // Assignment operator
    const loose_handle<value_type> &
    operator=(const loose_handle<value_type> &x)
    {
        if (x.get() == obj) {
            return *this;
        }

        obj = x.get();
        return *this;
    }

    // Swaps the values of two handles without reference counts
    loose_handle<value_type> &
    swap(loose_handle<value_type> &x)
    {
        pointer ptr = x.obj;
        x.obj = obj;
        obj = ptr;
        return *this;
    }

    // Handle release procedure
    void detach()
    {
        obj = 0;
    }

    // This will be reintroduced with a new function

    void reset()
    {
        detach();
    }

    bool empty()const
    {
        return obj == 0;
    }

    // Returns a constant handle to our object
    loose_handle<const value_type> constant()const
    {
        return *this;
    }

    // Returns number of instances
    count_type
    count()const
    {
        return obj ? obj->count() : 0;
    }

    reference
    operator*()const
    {
        assert(obj);
        return *obj;
    }

    pointer
    operator->()const
    {
        assert(obj);
        return obj;
    }

    // static_cast<> overload

    // static_cast<> overload (for consts)
    operator loose_handle<const value_type>()const
    {
        return loose_handle<const value_type>(static_cast<const_pointer>(obj));
    }

    operator handle<value_type>()const
    {
        return handle<value_type>(obj);
    }

    operator rhandle<value_type>()const
    {
        return rhandle<value_type>(obj);
    }

    // Returns pointer to the object that is being wrapped
    pointer get()const
    {
        return obj;
    }

    // More explicit bool cast
    operator bool()const
    {
        return obj != 0;
    }

    bool
    operator!()const
    {
        return !obj;
    }

    void ref()
    {
        if (obj) {
            obj->ref();
        }
    }

    bool unref()
    {
        if (obj && !obj->unref()) {
            obj = 0;
            return false;
        }

        return true;
    }

    template<typename U>
    bool type_is() const
    {
        return dynamic_cast<const U*>(obj);
    }

    template<typename U>
    U* type_pointer() const
    {
        return dynamic_cast<U*>(obj);
    }

    template<typename U>
    bool type_equal() const
    {
        return typeid(*obj) == typeid(U);
    }
}; // END of template class loose_handle

template <class T> template <class U> handle<T> handle<T>::cast_static(const loose_handle<U>& x)
{
    return handle<T>(static_cast	 <T*>(x.get()));
}
template <class T> template <class U> handle<T> handle<T>::cast_dynamic(const loose_handle<U>& x)
{
    return handle<T>(dynamic_cast	 <T*>(x.get()));
}
template <class T> template <class U> handle<T> handle<T>::cast_const(const loose_handle<U>& x)
{
    return handle<T>(const_cast		 <T*>(x.get()));
}
template <class T> template <class U> handle<T> handle<T>::cast_reinterpret(const loose_handle<U>& x)
{
    return handle<T>(reinterpret_cast<T*>(x.get()));
}

template <class T> template <class U> handle<T> handle<T>::cast_static(const rhandle<U>&	   x)
{
    return handle<T>(static_cast	 <T*>(x.get()));
}
template <class T> template <class U> handle<T> handle<T>::cast_dynamic(const rhandle<U>&	   x)
{
    return handle<T>(dynamic_cast	 <T*>(x.get()));
}
template <class T> template <class U> handle<T> handle<T>::cast_const(const rhandle<U>&	   x)
{
    return handle<T>(const_cast		 <T*>(x.get()));
}
template <class T> template <class U> handle<T> handle<T>::cast_reinterpret(const rhandle<U>&	   x)
{
    return handle<T>(reinterpret_cast<T*>(x.get()));
}

template <class T> template <class U> handle<T> handle<T>::cast_static(U*					   x)
{
    return handle<T>(static_cast	 <T*>(x));
}
template <class T> template <class U> handle<T> handle<T>::cast_dynamic(U*					   x)
{
    return handle<T>(dynamic_cast	 <T*>(x));
}
template <class T> template <class U> handle<T> handle<T>::cast_const(U*					   x)
{
    return handle<T>(const_cast		 <T*>(x));
}
template <class T> template <class U> handle<T> handle<T>::cast_reinterpret(U*					   x)
{
    return handle<T>(reinterpret_cast<T*>(x));
}

template <class T, class U> bool operator==(const handle		 <T>& lhs, const handle		<U>& rhs)
{
    return (lhs.get() == rhs.get());
}
template <class T, class U> bool operator==(const loose_handle<T>& lhs, const loose_handle<U>& rhs)
{
    return (lhs.get() == rhs.get());
}
template <class T, class U> bool operator==(const handle		 <T>& lhs, const loose_handle<U>& rhs)
{
    return (lhs.get() == rhs.get());
}
template <class T, class U> bool operator==(const loose_handle<T>& lhs, const handle		<U>& rhs)
{
    return (lhs.get() == rhs.get());
}
template <class T>		   bool operator==(const handle<T>&		  lhs, const T*				 rhs)
{
    return (lhs.get() == rhs);
}
template <class T>		   bool operator==(const loose_handle<T>& lhs, const T*				 rhs)
{
    return (lhs.get() == rhs);
}
template <class T>		   bool operator==(const T*				  lhs, const handle<T>&		 rhs)
{
    return (lhs		 == rhs.get());
}
template <class T>		   bool operator==(const T*				  lhs, const loose_handle<T>& rhs)
{
    return (lhs		 == rhs.get());
}

template <class T, class U> bool operator!=(const handle		 <T>& lhs, const handle		<U>& rhs)
{
    return (lhs.get() != rhs.get());
}
template <class T, class U> bool operator!=(const loose_handle<T>& lhs, const loose_handle<U>& rhs)
{
    return (lhs.get() != rhs.get());
}
template <class T, class U> bool operator!=(const handle		 <T>& lhs, const loose_handle<U>& rhs)
{
    return (lhs.get() != rhs.get());
}
template <class T, class U> bool operator!=(const loose_handle<T>& lhs, const handle		<U>& rhs)
{
    return (lhs.get() != rhs.get());
}
template <class T>		   bool operator!=(const handle<T>&		  lhs, const T*				 rhs)
{
    return (lhs.get() != rhs);
}
template <class T>		   bool operator!=(const loose_handle<T>& lhs, const T*				 rhs)
{
    return (lhs.get() != rhs);
}
template <class T>		   bool operator!=(const T*				  lhs, const handle<T>&		 rhs)
{
    return (lhs		 != rhs.get());
}
template <class T>		   bool operator!=(const T*				  lhs, const loose_handle<T>& rhs)
{
    return (lhs		 != rhs.get());
}

template <class T, class U> bool operator<(const handle<T>&		  lhs, const handle<U>&		 rhs)
{
    return (lhs.get() < rhs.get());
}
template <class T, class U> bool operator<(const loose_handle<T>&  lhs, const loose_handle<U>& rhs)
{
    return (lhs.get() < rhs.get());
}
template <class T, class U> bool operator<(const handle<T>&		  lhs, const loose_handle<U>& rhs)
{
    return (lhs.get() < rhs.get());
}
template <class T, class U> bool operator<(const loose_handle<T>&  lhs, const handle<U>&		 rhs)
{
    return (lhs.get() < rhs.get());
}
template <class T>		   bool operator<(const handle<T>&		  lhs, const T*				 rhs)
{
    return (lhs.get() < rhs);
}
template <class T>		   bool operator<(const loose_handle<T>&  lhs, const T*				 rhs)
{
    return (lhs.get() < rhs);
}
template <class T>		   bool operator<(const T*				  lhs, const handle<T>&		 rhs)
{
    return (lhs		 < rhs.get());
}
template <class T>		   bool operator<(const T*				  lhs, const loose_handle<T>& rhs)
{
    return (lhs		 < rhs.get());
}

_ETL_END_NAMESPACE

#endif